/*! \file: test_object.c
 *
 */

#include <check.h>
#include <gsl/gsl_errno.h>
#include <gsl/gsl_vector.h>
#include <gsl/gsl_complex.h>
#include "tests.h"
#include "gico_object.h"

START_TEST (object_creation_destruction)
{
	int ret;
	gico_object *test;

	/* allocate the object */
	ret = gico_object_alloc(&test, 10, 10, GICO_REAL);

	/* check if it allocated correctly */
	fail_unless(ret == GSL_SUCCESS, "Unable to allocate the gico_object.");

	/* Deallocate the object */
	ret = gico_object_dealloc(test);

	/* check if it deallocated correctly */
	fail_unless(ret == GSL_SUCCESS, "Unable to deallocate the gico_object.");
}
END_TEST

START_TEST (object_get_set_value)
{
	int ret;
	double value_in, value_out;
	gico_object *test;

	/* allocate the object */
	ret = gico_object_alloc(&test, 10, 10, GICO_REAL);

	/* set the value */
	value_in = -3.52;
	ret = gico_object_set_value(test, 3, 3, value_in);

	/* check if it failed */
	fail_unless(ret == GSL_SUCCESS, "Unable to set the value.");

	/* get the value */
	ret = gico_object_get_value(test, 3, 3, &value_out);

	/* check if it failed */
	fail_unless(ret == GSL_SUCCESS, "Unable to get the value.");

	/* check if both values coincide */
	fail_unless(value_out == value_in, "Get value differs from the set one.");

	/* Deallocate the object */
	ret = gico_object_dealloc(test);
}
END_TEST

START_TEST (object_get_set_cvalue)
{
	int ret;
	gsl_complex value_in, value_out;
	gico_object *test;

	/* allocate the object */
	ret = gico_object_alloc(&test, 10, 10, GICO_COMPLEX);

	/* initialize the complex value */
	GSL_SET_COMPLEX(&value_in, -1.35, 0.28);

	/* set the value into the gico_object */
	ret = gico_object_set_cvalue(test, 3, 3, value_in);

	/* check if it failed */
	fail_unless(ret == GSL_SUCCESS, "Unable to set the value.");

	/* get the value */
	ret = gico_object_get_cvalue(test, 3, 3, &value_out);

	/* check if it failed */
	fail_unless(ret == GSL_SUCCESS, "Unable to get the value.");

	/* check if both values coincide */
	fail_unless(GSL_COMPLEX_EQ(value_out, value_in), "Get value differs from the set one.");

	/* Deallocate the object */
	ret = gico_object_dealloc(test);
}
END_TEST

START_TEST (object_get_set_vector)
{
	int ret;
	gsl_vector *vector_in, *vector_out;
	gico_object *test;

	/* allocate the object */
	ret = gico_object_alloc(&test, 10, 10, GICO_REAL);

	/* allocate the vectors */
	vector_in = gsl_vector_alloc(3);
	vector_out = gsl_vector_alloc(3);

	/* set the values */
	gsl_vector_set(vector_in, 0, 0.12);
	gsl_vector_set(vector_in, 1, 0.13);
	gsl_vector_set(vector_in, 2, 0.14);

	/* set the data */
	ret = gico_object_set_vector(test, 3, 3, GICO_VER, vector_in);

	/* check if it failed */
	fail_unless(ret == GSL_SUCCESS, "Unable to set the vector.");

	/* set the data in a wrong place */
	ret = gico_object_set_vector(test, 8, 9, GICO_VER, vector_in);

	/* check if it failed */
	fail_unless(ret != GSL_SUCCESS, "Success returned in a wrong position.");

	/* get the value */
	ret = gico_object_get_vector(test, 3, 3, GICO_VER, vector_out);

	/* check if it failed */
	fail_unless(ret == GSL_SUCCESS, "Unable to get the vector.");

	/* check if both vectors coincide */
	fail_unless((gsl_vector_get(vector_in, 0) == gsl_vector_get(vector_out, 0)) &&
			    (gsl_vector_get(vector_in, 1) == gsl_vector_get(vector_out, 1)) &&
			    (gsl_vector_get(vector_in, 2) == gsl_vector_get(vector_out, 2)), "Get vector differs from the set one.");

	/* deallocate the vectors */
	gsl_vector_free(vector_in);
	gsl_vector_free(vector_out);

	/* Deallocate the object */
	ret = gico_object_dealloc(test);
}
END_TEST

START_TEST (object_get_set_cvector)
{
	int ret;
	gsl_vector_complex *vector_in, *vector_out;
	gsl_complex cvalue;
	gico_object *test;

	/* allocate the object */
	ret = gico_object_alloc(&test, 10, 10, GICO_COMPLEX);

	/* allocate the vectors */
	vector_in = gsl_vector_complex_alloc(3);
	vector_out = gsl_vector_complex_alloc(3);

	/* set the values */
	GSL_SET_COMPLEX(&cvalue, 0.12, 0.15);
	gsl_vector_complex_set(vector_in, 0, cvalue);
	GSL_SET_COMPLEX(&cvalue, 0.13, 0.16);
	gsl_vector_complex_set(vector_in, 1, cvalue);
	GSL_SET_COMPLEX(&cvalue, 0.14, 0.17);
	gsl_vector_complex_set(vector_in, 2, cvalue);

	/* set the data */
	ret = gico_object_set_cvector(test, 3, 3, GICO_VER, vector_in);

	/* check if it failed */
	fail_unless(ret == GSL_SUCCESS, "Unable to set the vector.");

	/* set the data in a wrong place */
	ret = gico_object_set_cvector(test, 8, 9, GICO_VER, vector_in);

	/* check if it failed */
	fail_unless(ret != GSL_SUCCESS, "Success returned in a wrong position.");

	/* get the value */
	ret = gico_object_get_cvector(test, 3, 3, GICO_VER, vector_out);

	/* check if it failed */
	fail_unless(ret == GSL_SUCCESS, "Unable to get the vector.");

	/* check if both vectors coincide */
	fail_unless(GSL_COMPLEX_EQ(gsl_vector_complex_get(vector_in, 0), gsl_vector_complex_get(vector_out, 0)) &&
				GSL_COMPLEX_EQ(gsl_vector_complex_get(vector_in, 1), gsl_vector_complex_get(vector_out, 1)) &&
				GSL_COMPLEX_EQ(gsl_vector_complex_get(vector_in, 2), gsl_vector_complex_get(vector_out, 2)), "Get vector differs from the set one.");

	/* deallocate the vectors */
	gsl_vector_complex_free(vector_in);
	gsl_vector_complex_free(vector_out);

	/* Deallocate the object */
	ret = gico_object_dealloc(test);
}
END_TEST

START_TEST (object_get_set_matrix)
{
	int ret, i, j;
	gsl_matrix *matrix_in, *matrix_out;
	gico_object *test;

	/* allocate the object */
	ret = gico_object_alloc(&test, 10, 10, GICO_REAL);

	/* allocate the matrices */
	matrix_in = gsl_matrix_alloc(3, 3);
	matrix_out = gsl_matrix_alloc(3, 3);

	/* set the values */
	gsl_matrix_set(matrix_in, 0, 0, 0.00);
	gsl_matrix_set(matrix_in, 0, 1, 0.01);
	gsl_matrix_set(matrix_in, 0, 2, 0.02);
	gsl_matrix_set(matrix_in, 1, 0, 0.10);
	gsl_matrix_set(matrix_in, 1, 1, 0.11);
	gsl_matrix_set(matrix_in, 1, 2, 0.12);
	gsl_matrix_set(matrix_in, 2, 0, 0.20);
	gsl_matrix_set(matrix_in, 2, 1, 0.21);
	gsl_matrix_set(matrix_in, 2, 2, 0.22);

	/* set the data */
	ret = gico_object_set_matrix(test, 3, 3, matrix_in);

	/* check if it failed */
	fail_unless(ret == GSL_SUCCESS, "Unable to set the matrix.");

	/* set the data in a wrong place */
	ret = gico_object_set_matrix(test, 8, 9, matrix_in);

	/* check if it failed */
	fail_unless(ret != GSL_SUCCESS, "Success returned in a wrong position.");

	/* get the value */
	ret = gico_object_get_matrix(test, 3, 3, matrix_out);

	/* check if it failed */
	fail_unless(ret == GSL_SUCCESS, "Unable to get the matrix.");

	/* check if both matrices coincide */
	ret = GSL_SUCCESS;
	for (i=0; i<3; i++)
	{
		for (j=0; j<3; j++)
		{
			if (gsl_matrix_get(matrix_in, i, j) != gsl_matrix_get(matrix_out, i, j))
			{
				ret = GSL_FAILURE;
				break;
			}
		}
	}
	fail_unless(ret == GSL_SUCCESS, "Get matrix differs from the set one.");

	/* deallocate the vectors */
	gsl_matrix_free(matrix_in);
	gsl_matrix_free(matrix_out);

	/* Deallocate the object */
	ret = gico_object_dealloc(test);
}
END_TEST

START_TEST (object_get_set_cmatrix)
{
	int ret, i, j;
	gsl_matrix_complex *matrix_in, *matrix_out;
	gsl_complex cvalue;
	gico_object *test;

	/* allocate the object */
	ret = gico_object_alloc(&test, 10, 10, GICO_COMPLEX);

	/* allocate the matrices */
	matrix_in = gsl_matrix_complex_alloc(3, 3);
	matrix_out = gsl_matrix_complex_alloc(3, 3);

	/* set the values */
	GSL_SET_COMPLEX(&cvalue, 0.00, 1.00);
	gsl_matrix_complex_set(matrix_in, 0, 0, cvalue);
	GSL_SET_COMPLEX(&cvalue, 0.01, 1.01);
	gsl_matrix_complex_set(matrix_in, 0, 1, cvalue);
	GSL_SET_COMPLEX(&cvalue, 0.02, 1.02);
	gsl_matrix_complex_set(matrix_in, 0, 2, cvalue);
	GSL_SET_COMPLEX(&cvalue, 0.00, 1.00);
	gsl_matrix_complex_set(matrix_in, 1, 0, cvalue);
	GSL_SET_COMPLEX(&cvalue, 0.01, 1.01);
	gsl_matrix_complex_set(matrix_in, 1, 1, cvalue);
	GSL_SET_COMPLEX(&cvalue, 0.02, 1.02);
	gsl_matrix_complex_set(matrix_in, 1, 2, cvalue);
	GSL_SET_COMPLEX(&cvalue, 0.00, 1.00);
	gsl_matrix_complex_set(matrix_in, 2, 0, cvalue);
	GSL_SET_COMPLEX(&cvalue, 0.01, 1.01);
	gsl_matrix_complex_set(matrix_in, 2, 1, cvalue);
	GSL_SET_COMPLEX(&cvalue, 0.02, 1.02);
	gsl_matrix_complex_set(matrix_in, 2, 2, cvalue);

	/* set the data */
	ret = gico_object_set_cmatrix(test, 3, 3, matrix_in);

	/* check if it failed */
	fail_unless(ret == GSL_SUCCESS, "Unable to set the matrix.");

	/* set the data in a wrong place */
	ret = gico_object_set_cmatrix(test, 8, 9, matrix_in);

	/* check if it failed */
	fail_unless(ret != GSL_SUCCESS, "Success returned in a wrong position.");

	/* get the value */
	ret = gico_object_get_cmatrix(test, 3, 3, matrix_out);

	/* check if it failed */
	fail_unless(ret == GSL_SUCCESS, "Unable to get the matrix.");

	/* check if both matrices coincide */
	ret = GSL_SUCCESS;
	for (i=0; i<3; i++)
	{
		for (j=0; j<3; j++)
		{
			if (!GSL_COMPLEX_EQ(gsl_matrix_complex_get(matrix_in, i, j), gsl_matrix_complex_get(matrix_out, i, j)))
			{
				ret = GSL_FAILURE;
				break;
			}
		}
	}
	fail_unless(ret == GSL_SUCCESS, "Get matrix differs from the set one.");

	/* deallocate the vectors */
	gsl_matrix_complex_free(matrix_in);
	gsl_matrix_complex_free(matrix_out);

	/* Deallocate the object */
	ret = gico_object_dealloc(test);
}
END_TEST

START_TEST (object_load_save_real)
{
	int ret, i, j;
	gsl_matrix *matrix_in, *matrix_out;
	gico_object *test_in, *test_out;

	/* allocate the object */
	ret = gico_object_alloc(&test_in, 10, 10, GICO_REAL);
	test_in->d[0] = 0.123;
	test_in->d[1] = 0.321;

	/* allocate the matrices */
	matrix_in = gsl_matrix_alloc(3, 3);
	matrix_out = gsl_matrix_alloc(3, 3);

	/* set the values */
	gsl_matrix_set(matrix_in, 0, 0, 0.00);
	gsl_matrix_set(matrix_in, 0, 1, 0.01);
	gsl_matrix_set(matrix_in, 0, 2, 0.02);
	gsl_matrix_set(matrix_in, 1, 0, 0.10);
	gsl_matrix_set(matrix_in, 1, 1, 0.11);
	gsl_matrix_set(matrix_in, 1, 2, 0.12);
	gsl_matrix_set(matrix_in, 2, 0, 0.20);
	gsl_matrix_set(matrix_in, 2, 1, 0.21);
	gsl_matrix_set(matrix_in, 2, 2, 0.22);

	/* set the data */
	ret = gico_object_set_matrix(test_in, 3, 3, matrix_in);

	/* save the gico_object */
	ret = gico_object_save(test_in, "test.dat");

	/* check if it failed */
	fail_unless(ret == GSL_SUCCESS, "Unable to save the gico_object: %d.", ret);

	/* load the gico_object */
	ret = gico_object_load("test.dat", &test_out);

	/* check if it failed */
	fail_unless(ret == GSL_SUCCESS, "Unable to load the gico_object: %d.", ret);

	/* get the value */
	ret = gico_object_get_matrix(test_out, 3, 3, matrix_out);

	/* check if both matrices coincide */
	ret = GSL_SUCCESS;
	for (i=0; i<3; i++)
	{
		for (j=0; j<3; j++)
		{
			if (gsl_matrix_get(matrix_in, i, j) != gsl_matrix_get(matrix_out, i, j))
			{
				ret = GSL_FAILURE;
				break;
			}
		}
	}
	fail_unless(ret == GSL_SUCCESS, "Get matrix differs from the set one.");

	/* deallocate the matrices */
	gsl_matrix_free(matrix_in);
	gsl_matrix_free(matrix_out);

	/* deallocate the objects */
	ret = gico_object_dealloc(test_in);
	ret = gico_object_dealloc(test_out);
}
END_TEST

START_TEST (object_load_save_complex)
{
	int ret, i, j;
	gsl_matrix_complex *matrix_in, *matrix_out;
	gsl_complex cvalue;
	gico_object *test_in, *test_out;

	/* allocate the object */
	ret = gico_object_alloc(&test_in, 10, 10, GICO_COMPLEX);

	/* allocate the matrices */
	matrix_in = gsl_matrix_complex_alloc(3, 3);
	matrix_out = gsl_matrix_complex_alloc(3, 3);

	/* set the values */
	GSL_SET_COMPLEX(&cvalue, 0.00, 1.00);
	gsl_matrix_complex_set(matrix_in, 0, 0, cvalue);
	GSL_SET_COMPLEX(&cvalue, 0.01, 1.01);
	gsl_matrix_complex_set(matrix_in, 0, 1, cvalue);
	GSL_SET_COMPLEX(&cvalue, 0.02, 1.02);
	gsl_matrix_complex_set(matrix_in, 0, 2, cvalue);
	GSL_SET_COMPLEX(&cvalue, 0.00, 1.00);
	gsl_matrix_complex_set(matrix_in, 1, 0, cvalue);
	GSL_SET_COMPLEX(&cvalue, 0.01, 1.01);
	gsl_matrix_complex_set(matrix_in, 1, 1, cvalue);
	GSL_SET_COMPLEX(&cvalue, 0.02, 1.02);
	gsl_matrix_complex_set(matrix_in, 1, 2, cvalue);
	GSL_SET_COMPLEX(&cvalue, 0.00, 1.00);
	gsl_matrix_complex_set(matrix_in, 2, 0, cvalue);
	GSL_SET_COMPLEX(&cvalue, 0.01, 1.01);
	gsl_matrix_complex_set(matrix_in, 2, 1, cvalue);
	GSL_SET_COMPLEX(&cvalue, 0.02, 1.02);
	gsl_matrix_complex_set(matrix_in, 2, 2, cvalue);

	/* set the data */
	ret = gico_object_set_cmatrix(test_in, 3, 3, matrix_in);

	/* save the gico_object */
	ret = gico_object_save(test_in, "testc.dat");

	/* check if it failed */
	fail_unless(ret == GSL_SUCCESS, "Unable to save the gico_object (complex): %d", ret);

	/* load the gico_object */
	ret = gico_object_load("testc.dat", &test_out);

	/* check if it failed */
	fail_unless(ret == GSL_SUCCESS, "Unable to load the gico_object (complex): %d", ret);

	/* get the value */
	ret = gico_object_get_cmatrix(test_out, 3, 3, matrix_out);

	/* check if both matrices coincide */
	ret = GSL_SUCCESS;
	for (i=0; i<3; i++)
	{
		for (j=0; j<3; j++)
		{
			if (!GSL_COMPLEX_EQ(gsl_matrix_complex_get(matrix_in, i, j), gsl_matrix_complex_get(matrix_out, i, j)))
			{
				ret = GSL_FAILURE;
				break;
			}
		}
	}
	fail_unless(ret == GSL_SUCCESS, "Get matrix differs from the set one.");

	/* deallocate the matrices */
	gsl_matrix_complex_free(matrix_in);
	gsl_matrix_complex_free(matrix_out);

	/* Deallocate the object */
	ret = gico_object_dealloc(test_in);
	ret = gico_object_dealloc(test_out);
}
END_TEST

START_TEST (object_save_gnuplot)
{
	int ret, i;
	gico_object *test;
	gsl_complex c;

	/* allocate the object */
	ret = gico_object_alloc(&test, 5, 5, GICO_COMPLEX);
	test->d[0] = 0.1;
	test->d[1] = 0.2;

	/* set the values to form a pyramid */
	for (i=0; i<4; i++)
	{
		GSL_SET_COMPLEX(&c, 1.0, 1.0);
		gico_object_set_cvalue(test, 0, i, c);
		GSL_SET_COMPLEX(&c, 1.0, 2.0);
		gico_object_set_cvalue(test, i, 4, c);
		GSL_SET_COMPLEX(&c, 1.0, 3.0);
		gico_object_set_cvalue(test, 4, 4-i, c);
		GSL_SET_COMPLEX(&c, 1.0, 4.0);
		gico_object_set_cvalue(test, 4-i, 0, c);
	}
	for (i=0; i<2; i++)
	{
		GSL_SET_COMPLEX(&c, 5.0, 5.0);
		gico_object_set_cvalue(test, 1, 1+i, c);
		GSL_SET_COMPLEX(&c, 5.0, 4.0);
		gico_object_set_cvalue(test, 1+i, 3, c);
		GSL_SET_COMPLEX(&c, 5.0, 3.0);
		gico_object_set_cvalue(test, 3, 3-i, c);
		GSL_SET_COMPLEX(&c, 5.0, 2.0);
		gico_object_set_cvalue(test, 3-i, 1, c);
	}
	GSL_SET_COMPLEX(&c, 15.0, 15.0);
	gico_object_set_cvalue(test, 2, 2, c);

	/* save as gnuplot */
	ret = gico_object_save_gnuplot(test, GICO_REAL, "test_re.gnu");

	/* check if it failed */
	fail_unless(ret == GSL_SUCCESS, "Unable to save the gico_object as real gnuplot: %d", ret);

	/* save as gnuplot */
	ret = gico_object_save_gnuplot(test, GICO_ABS2, "test_a2.gnu");

	/* check if it failed */
	fail_unless(ret == GSL_SUCCESS, "Unable to save the gico_object as abs2 gnuplot: %d", ret);

	/* save as gnuplot */
	ret = gico_object_save_gnuplot(test, GICO_ANGLE, "test_an.gnu");

	/* check if it failed */
	fail_unless(ret == GSL_SUCCESS, "Unable to save the gico_object as angle gnuplot: %d", ret);

	/* deallocate the object */
	ret = gico_object_dealloc(test);
}
END_TEST

Suite *test_suite(void)
{
	Suite *s = suite_create("SIGNAL");

	TCase *tc_core = tcase_create("Core");
	tcase_add_test(tc_core, object_creation_destruction);
	tcase_add_test(tc_core, object_get_set_value);
	tcase_add_test(tc_core, object_get_set_cvalue);
	tcase_add_test(tc_core, object_get_set_vector);
	tcase_add_test(tc_core, object_get_set_cvector);
	tcase_add_test(tc_core, object_get_set_matrix);
	tcase_add_test(tc_core, object_get_set_cmatrix);
	tcase_add_test(tc_core, object_load_save_real);
	tcase_add_test(tc_core, object_load_save_complex);
	tcase_add_test(tc_core, object_save_gnuplot);
	suite_add_tcase(s, tc_core);

	return s;
}

int main(void)
{
	int number_failed;

	Suite *s = test_suite();
	SRunner *sr = srunner_create(s);
	srunner_run_all(sr, CK_NORMAL);
	number_failed = srunner_ntests_failed(sr);
	srunner_free(sr);

	return (number_failed == 0) ? GSL_SUCCESS : GSL_FAILURE;
}
